package com.itlong.cloud.intercept.sdkV2;

import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.PO.OperateUserInfoPO;
import com.itlong.cloud.POJO.PO.PropertyUserInfoPO;
import com.itlong.cloud.POJO.VO.MessageVO;
import com.itlong.cloud.POJO.VO.SDKMessageVO;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.OperateSystemSetUpEnum;
import com.itlong.cloud.enumerate.PropertyPublicRoleEnum;
import com.itlong.cloud.enumerate.ecode.BaseErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.CloudTalkErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.OperateErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.SDKErrorCodeEnum;
import com.itlong.cloud.intercept.sdkV1.CloudTalkSDKServerLoginIntercept;
import com.itlong.cloud.user.operate.IOperatePropertyAccountServiceClient;
import com.itlong.cloud.user.operate.IOperateUserInfoServiceClient;
import com.itlong.cloud.user.sdk.ICloudTalkSDKAppUserServiceClient;
import com.itlong.cloud.user.sdk.ICloudTalkSDKServerUserServiceClient;
import com.itlong.cloud.user.sdk.ISDKServerOldUserServiceClient;
import com.itlong.cloud.utils.encrypt.DesEncryptUtil;
import com.itlong.cloud.utils.encrypt.Md5EncryptUtil;
import com.itlong.cloud.utils.network.http.HttpProtocolUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <desc>
 * 云设备 入参处理拦截器
 * </desc>
 *
 * @createDate 2019/09/16
 */
@Aspect
@Component
public class SDKCloudDeviceParamIntercept {
    private static Logger LOG = LoggerFactory.getLogger(CloudTalkSDKServerLoginIntercept.class);

    @Autowired
    ICloudTalkSDKServerUserServiceClient iCloudTalkSDKServerUserServiceClient;

    @Autowired
    ISDKServerOldUserServiceClient iSDKUserServiceClient;

    @Autowired
    ICloudTalkSDKAppUserServiceClient iCloudTalkSDKAppUserServiceClient;

    @Autowired
    IOperateUserInfoServiceClient iOperateUserInfoServiceClient;

    @Autowired
    IOperatePropertyAccountServiceClient iOperatePropertyAccountServiceClient;

    // 定义一个切入点
    @Pointcut("(execution(* com.itlong.cloud.controller.sdkV2.base.*.*(..)) || execution(* com.itlong.cloud.controller.sdkV2.elevator.*.*(..))" +
            "|| execution(* com.itlong.cloud.controller.sdkV2.entrance.*.*(..)) || execution(* com.itlong.cloud.controller.sdkV2.face.*.*(..)) " +
            "|| execution(* com.itlong.cloud.controller.sdkV2.intercom.server.SDKCloudTalkEquipController.*(..))|| execution(* com.itlong.cloud.controller.sdkV2.intercom.server.SDKCloudTalkUserController.*(..)))" +
            "&& !@annotation(com.itlong.cloud.annotation.UnAuthAccessRequired)")
    public void excudeService() {
    }

    /**
     * <desc>
     * 云设备 入参token拦截器
     * </desc>
     *
     * @param thisJoinPoint
     * @return
     * @author Qiang.S
     * @createDate 2019/09/16
     */
    @Around("excudeService()")
    public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String token = request.getParameter("token");
        String responseTimestamp = new Date().getTime()+"";
        Date nowTime = new Date();
        if (StringUtils.isBlank(token)) { //无token
            return new SDKMessageVO(SDKErrorCodeEnum.SDK_PARAM_TOKEN_ERR.getErrorCode(),"",responseTimestamp,"");//此时没有加密签名直接明文返回报错信息
        }
        //兼容没有项目的账号退出robotGo
        String uri = request.getRequestURI();
        boolean logoutFlag = false;
        if (uri.contains("logout")){
            logoutFlag = true;
        }
        PropertyUserInfoPO propertyUserInfoPO = iCloudTalkSDKAppUserServiceClient.developerRetrieve(token);
        if (propertyUserInfoPO == null) { //appId 错误导致无法查询出开发者信息
            return new SDKMessageVO(SDKErrorCodeEnum.SDK_PARAM_TOKEN_ERR.getErrorCode(),"",responseTimestamp,"");//此时没有加密签名直接明文返回报错信息
        }
        PropertyUserInfoPO statusPO = iSDKUserServiceClient.getPropertyUserByAppId(propertyUserInfoPO.getUserId());
        //为了兼容工程人员登录，再查运营用户信息表
        if (statusPO == null){
            statusPO = new PropertyUserInfoPO();
            OperateUserInfoPO po = new OperateUserInfoPO();
            po.setUserId(propertyUserInfoPO.getUserId());
            OperateUserInfoPO userInfoPO = iOperateUserInfoServiceClient.getOne(po);
            if (userInfoPO == null){
                statusPO.setStatus(DataStatusEnum.DELETE.getType());
            }else {
                statusPO.setStatus(userInfoPO.getStatus());
            }
        }
        if (statusPO.getStatus() != 1) {
            return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(SDKErrorCodeEnum.SDK_DEVELOPER_STATUS_ERR.getErrorCode(),"",responseTimestamp,""), propertyUserInfoPO.getAppsecret());
        }

        //判断机器人账号授权是否过有效期，
        // 为了区分robotgo调用sdk接口和直接调用sdk接口现在使用loginType字段区分，直接调用sdk接口不存储loginType
        if (PropertyPublicRoleEnum.ROBOT_DEVELOPER.getRoleId().equals(statusPO.getRoleId())
                && "1".equals(propertyUserInfoPO.getLoginType())
                && (nowTime.before(statusPO.getEffectStartTime())
                    || nowTime.after(statusPO.getEffectEndTime()))) {
            return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(OperateErrorCodeEnum.USER_ACCOUNT_EXPIRE_ERR.getErrorCode(), "", responseTimestamp, ""), propertyUserInfoPO.getAppsecret());
        }

        String requestId;
        Map<String, Object> params;
        try {
            //入参密文
            String encryptScript = request.getParameter("encryptScript");

            if (StringUtils.isBlank(encryptScript)) { //加密串未携带，参数异常
                return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(BaseErrorCodeEnum.PARAM_ERR.getErrorCode(),"",responseTimestamp,""), propertyUserInfoPO.getAppsecret());
            } else {
                //解密入参
                String encryptResult = DesEncryptUtil.aesDecrypt(encryptScript, propertyUserInfoPO.getAppsecret());
                encryptResult = encryptResult.replaceAll("&quot;","\"");
                if (encryptResult == null) {
                    return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(BaseErrorCodeEnum.PARAM_ERR.getErrorCode(),"",responseTimestamp,""), propertyUserInfoPO.getAppsecret());
                }

                JSONObject jsStr = JSONObject.parseObject(encryptResult);//入参转json
                requestId = jsStr.get("requestId") == null ? "" : jsStr.get("requestId").toString();
                String timestamp = jsStr.get("timestamp") == null ? "" : jsStr.get("timestamp").toString();
                request.setAttribute("requestId", requestId);
                request.setAttribute("timestamp", timestamp);
                JSONObject protocol = JSONObject.parseObject(jsStr.get("protocol").toString());
                request.setAttribute("version", protocol.get("version") == null ? "" : protocol.get("version").toString());
                JSONObject client = JSONObject.parseObject(jsStr.get("client").toString());
                JSONObject param = JSONObject.parseObject(jsStr.get("param").toString());
                params = JsonUtil.toObject(protocol.toString(), HashMap.class);
                params.putAll(JsonUtil.toObject(client.toString(), HashMap.class));
                params.putAll(JsonUtil.toObject(param.toString(), HashMap.class));
                params.remove("appSecret");

                //验签
                String sign = jsStr.get("sign").toString();
                if (!Md5EncryptUtil.checkSDKV2Sign(params, sign, requestId, timestamp, propertyUserInfoPO.getAppsecret())) {
                    return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(CloudTalkErrorCodeEnum.SERVER_MD5_ERROR.getErrorCode(),requestId,responseTimestamp,""), propertyUserInfoPO.getAppsecret());
                }
                params.put("requestId",requestId);
                HttpProtocolUtil.setRequestAttributes(params, request);
                //通过appId appSecret来进行服务认证
                if (StringUtils.isNotBlank(propertyUserInfoPO.getUserId()) && StringUtils.isNotBlank(propertyUserInfoPO.getAppsecret())) {
                    // 校验开发者账号是否有该项目的权限
                    List<String> projectIdList = iCloudTalkSDKServerUserServiceClient.getProjectIdByParams(propertyUserInfoPO.getUserId());
                    //兼容工程人员登录robotGo
                    if (projectIdList == null || projectIdList.isEmpty()){
                        projectIdList = iOperatePropertyAccountServiceClient.getEngineerProjectIds(propertyUserInfoPO.getUserId());
                    }
                    if (params.get("projectId") == null || params.get("projectId") == "" && !logoutFlag) {
                        return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(SDKErrorCodeEnum.SDK_DEVELOPER_PROJECT_IS_NULL.getErrorCode(),requestId,responseTimestamp,""), propertyUserInfoPO.getAppsecret());
                    }
                    if ((projectIdList == null || !projectIdList.contains(params.get("projectId"))) && !logoutFlag) {
                        return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(CloudTalkErrorCodeEnum.SERVER_CHECKDEVELOPER_AUTH.getErrorCode(),requestId,responseTimestamp,""), propertyUserInfoPO.getAppsecret());
                    }
                    request.setAttribute("appId",propertyUserInfoPO.getUserId());
                    request.setAttribute("appSecret",propertyUserInfoPO.getAppsecret());
                    request.setAttribute("roleId",propertyUserInfoPO.getRoleId());
                    Object result = thisJoinPoint.proceed();
                    //加密
                    SDKMessageVO messageVO = (SDKMessageVO) result;
                    return DesEncryptUtil.getEncryptResultSDKV2(messageVO, propertyUserInfoPO.getAppsecret());
                } else {
                    return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(BaseErrorCodeEnum.NOT_PARAM.getErrorCode(),requestId,responseTimestamp,""), propertyUserInfoPO.getAppsecret());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DesEncryptUtil.getEncryptResultSDKV2(new SDKMessageVO(BaseErrorCodeEnum.ERROR.getErrorCode(),"",responseTimestamp,""), propertyUserInfoPO.getAppsecret());
        }
    }
}